
import type { includes } from 'lodash';
<template>
  <div class="codeContainer">
    <div class="flex flex-column justify-content-center">
      <Splitter class="h-25rem">
        <SplitterPanel :size="33" :minSize="10" class="p-2 surface-800">
          <Fieldset legend="React" class="h-full">
            <ReactCoder ref="reactRef" />
          </Fieldset>
        </SplitterPanel>
      </Splitter>
      <Button class="m-3" label="运行" @click="runCode" />
    </div>
    <div id="iframeBox" class="h-20rem bg-white"></div>
  </div>
</template>

<script setup lang="ts">
import { Splitter, SplitterPanel, Fieldset, Button } from '@/utils/primevue'
import { transform } from '@babel/standalone';
import { type PluginObj, types as t, NodePath } from '@babel/core';
import ReactCoder from '../components/ReactCoder.vue'
import { ref, type IframeHTMLAttributes } from 'vue';
import reactHtml from '../components/react.html?raw' // 已文本形式引入

const reactRef = ref()

const transformImportSourcePlugin: (pathMap: Record<string, string>) => PluginObj = (pathMap) => {
  return {
    visitor: {
      ImportDeclaration(path: NodePath<t.ImportDeclaration>) {
        const p = path.node.source.value // 原地址 ./App.tsx
        if (pathMap[p]) {
          path.node.source.value = pathMap[p];
        }
      }
    },
  }
}

/**
 *
 * @param codeStr 待编译代码
 * @param filename 文件名
 * @param pathMap 路径映射 { "./App.tsx": "blob url"}
 */
const transformCode = (codeStr: string, filename: string, pathMap: Record<string, string>): { code: string } => {
  if (codeStr) {
    const res = transform(codeStr, {
      presets: ['react', 'typescript'],
      filename,
      plugins: [transformImportSourcePlugin(pathMap)],
    });
    return { code: res?.code || '' }
  }
  return { code: '' }
}

const transformHtml = (appCode: string) => {
  if (appCode) {
    // App.tsx 组件
    const blobUrl = URL.createObjectURL(new Blob([appCode], { type: 'text/javascript' }))
    // 提取 reactHtml 中的 script module 代码
    const reactHtmlScript = reactHtml.match(/<script type="module">([\s\S]*?)<\/script>/)?.[1]
    const newHtml = transformCode(reactHtmlScript || '', 'index.html', { './App.tsx': blobUrl }).code
    // console.log('newHtml', newHtml)
    return reactHtml.replace(
      /<script type="module">[\s\S]*?<\/script>/,
      `<script type="module">\n${newHtml}\n<\/script>`
    );
  }
  return reactHtml
}

const runCode = () => {

  const appCode = transformCode(reactRef.value?.reactCode, 'App.tsx', {})
  // console.log('appCode', appCode)
  const res = transformHtml(appCode.code)
  // console.log('转化结果', res);

  const divEl = document.getElementById('iframeBox') as HTMLDivElement
  divEl.firstChild && divEl.removeChild(divEl.firstChild)
  const iframe: HTMLIFrameElement = document.createElement('iframe')
  iframe.width = '100%'
  iframe.height = '100%'
  iframe.frameBorder = '0'
  iframe.src = URL.createObjectURL(new Blob([res], { type: 'text/html' }))
  divEl.appendChild(iframe)
}

</script>

<style lang="scss" scoped>
.codeContainer {
  :deep(.p-fieldset-content) {
    padding: 0;
  }
}
</style>
